/*
 * *
 *  * Created with IntelliJ RustRover.
 *  * Description:
 *  * Copyright Author: ZhenYi
 *  * DateTime: 2024/2/14 下午5:10
 *
 */

pub mod massage;
pub mod user;
pub mod error;
pub mod state;
pub mod config;
pub mod utensil;
pub mod middleware;
mod admin;

use std::sync::{Arc, Mutex};
use rustis::commands::ConnectionCommands;
use salvo::prelude::TcpListener;
use salvo::{Listener, Router, Server};
use crate::config::info::Master;
use crate::massage::EmailQueue;
use crate::state::pgsql::pgsql_connect;
use crate::state::redis::redis_connect;
use crate::utensil::basic_auth::BasicAuthQueue;
use crate::utensil::cookie_queue::CookieQueue;

#[tokio::main]
async fn main() -> std::io::Result<()> {
    // 初始化日志
    tracing_subscriber::fmt().init();

    // 读取配置文件
    let info = Master::new().unwrap();

    // 连接数据库
    let pgsql = pgsql_connect(&info).await;

    // 连接redis
    let redis = redis_connect(&info).await;


    // cookie队列配置
    let redis_cookie = Arc::new(Mutex::new(redis.clone()));
    let (cookie_sd, mut cookie_rc) =
        tokio::sync::mpsc::channel::<CookieQueue>(512);
    let cookie_local = utensil::cookie_local::LocalCookie::new(redis.clone(), cookie_sd);
    // 单开一个线程处理cookie队列
    // cookie队列是一个全局队列
    // 只有增删改会进入这个队列
    // 查会直接从redis中查找
    // 然后由这个线程处理
    // 这样可以保证cookie的操作不会阻塞主线程
    // 也不会阻塞其他的异步任务
    tokio::spawn(async move {
        let redis_cookie = Arc::clone(&redis_cookie);
        while let Some(massage) = cookie_rc.recv().await {
            massage.match_ops(redis_cookie.clone()).await;
        }
    });

    // 邮件队列配置
    let email = EmailQueue::new(info.clone());
    let (email_sd, mut email_rc) =
        tokio::sync::mpsc::channel::<EmailQueue>(512);
    // 单开一个线程处理邮件队列
    // 邮件队列是一个全局队列
    // 所有的邮件都会进入这个队列
    // 然后由这个线程处理
    // 这样可以保证邮件的发送不会阻塞主线程
    // 也不会阻塞其他的异步任务
    tokio::spawn(async move {
        let info = Master::new().unwrap();
        while let Some(massage) = email_rc.recv().await {
            massage.send(email.clone(), info.email.clone());
        }
    });


    let (basic_sd,mut basic_rc) =
        tokio::sync::mpsc::channel::<BasicAuthQueue>(512);
    let redis_basic = redis_connect(&info).await;
    let basic_local = utensil::basic_local::LocalBasicAuth::new(redis_basic.clone(), basic_sd);
    redis.select(5).await.unwrap();
    tokio::spawn(async move {
        let redis_basic = Arc::new(Mutex::new(redis_basic));
        while let Some(massage) = basic_rc.recv().await {
            massage.match_ops(redis_basic.clone()).await;
        }
    });


    let route = Router::new()
        // 邮件队列
        .hoop(salvo::affix::inject(email_sd))
        // pgsql队列
        .hoop(salvo::affix::inject(pgsql))
        // redis连接
        // 主要提供给中间件使用
        // 在一般的路由中不需要使用
        .hoop(salvo::affix::inject(redis))
        // cookie本地Ops
        // 主要提供给中间件使用
        // 在路由表中需要使用，但是不要动就行了
        .hoop(salvo::affix::inject(cookie_local))
        // basic auth队列
        .hoop(salvo::affix::inject(basic_local))
        // 普通用户路由
        .push(user::user_route())
        // 管理端路由
        .push(admin::admin_route());
    // 作者端路由 todo
    // 专家端路由 todo
    // 学生端路由 todo


    // 启动服务器
    // 服务器使用的是salvo
    // Http服务器使用的是hyper
    // 协议是http1.1
    let acceptor = TcpListener::new(info.clone().local()).bind().await;
    Server::new(acceptor).serve(route).await;



    Ok(())
}

// 这是Https Quick协议的启动方式
//
// let config = RustlsConfig::new(Keycert::new().cert(cert.as_slice()).key(key.as_slice()));
//
//     let listener = TcpListener::new(("127.0.0.1", 5800)).rustls(config.clone());
//
//     let acceptor = QuinnListener::new(config, ("127.0.0.1", 5800))
//
//         .join(listener)
//
//         .bind()
//
//         .await;
//
//     Server::new(acceptor).serve(router).await;